﻿using System;

namespace Aeon.Emulator.Net
{
    /// <summary>
    /// Represents a full IPX internetwork address.
    /// </summary>
    public struct InternetworkAddress : IEquatable<InternetworkAddress>
    {
        private uint networkNumber;
        private NodeAddress nodeAddress;

        /// <summary>
        /// Initializes a new instance of the <see cref="InternetworkAddress"/> struct.
        /// </summary>
        /// <param name="networkNumber">The network number.</param>
        /// <param name="nodeAddress">The node address.</param>
        public InternetworkAddress(uint networkNumber, NodeAddress nodeAddress)
        {
            this.networkNumber = networkNumber;
            this.nodeAddress = nodeAddress;
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="addressA">The address A.</param>
        /// <param name="addressB">The address B.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator ==(InternetworkAddress addressA, InternetworkAddress addressB)
        {
            return addressA.Equals(addressB);
        }
        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="addressA">The address A.</param>
        /// <param name="addressB">The address B.</param>
        /// <returns>
        /// The result of the operator.
        /// </returns>
        public static bool operator !=(InternetworkAddress addressA, InternetworkAddress addressB)
        {
            return !addressA.Equals(addressB);
        }

        /// <summary>
        /// Gets the network number.
        /// </summary>
        public uint NetworkNumber
        {
            get { return this.networkNumber; }
        }
        /// <summary>
        /// Gets the node address.
        /// </summary>
        public NodeAddress NodeAddress
        {
            get { return this.nodeAddress; }
        }

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="other">An object to compare with this object.</param>
        /// <returns>
        /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
        /// </returns>
        public bool Equals(InternetworkAddress other)
        {
            return this.networkNumber == other.networkNumber && this.nodeAddress == other.nodeAddress;
        }
        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            if(obj is InternetworkAddress)
                return Equals((InternetworkAddress)obj);
            else
                return false;
        }
        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            return (int)this.networkNumber;
        }
        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("{0:X8}::{1}", this.networkNumber, this.nodeAddress);
        }
    }
}
